/**
 * @file drv_led.c
 * @brief LED灯带驱动 \n
 * @note 本驱动目前仅同时支持一个IO，需后期改进
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2020-11-30
 * @copyright Copyright (c) 2020  烽火通信
 ***************************************************************
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version  <th>Author  <th>Description
 * <tr><td>2020-11-30 <td>1.0      <td>wangh   <td>内容
 * </table>
 */ 
#include "drv_led.h"
#if DRV_LED_EN
#include "bsp.h"

#undef LOG_LEVEL_
#define LOG_LEVEL_  LOG_LVL_DEBUG
#include "bsp_log.h"


#if LED_USE_PWM
// #define MIN(a, b)   ({ typeof(a) a1 = a; typeof(b) b1 = b; a1 < b1 ? a1 : b1; })

/** @brief 一个LED的PWM数据结构 */
typedef struct 
{
    uint16_t b1[8];
    uint16_t b2[8];
    uint16_t b3[8];
} __attribute__((packed)) PWM_t;

static PWM_t LED_DMABuffer[LED_SIZE];   ///< DMA转换PWM脉冲缓存
SemaphoreHandle_t led_dmaTC_notify;     ///< DMA发送完成通知

#ifdef WS2812B_USE_GAMMA_CORRECTION
#ifdef WS2812B_USE_PRECALCULATED_GAMMA_TABLE
static const uint8_t LEDGammaTable[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
    2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
    10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21,
    22, 23, 23, 24, 24, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, 34, 35, 35, 36, 37, 38,
    38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58,
    59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 84,
    85, 86, 87, 88, 89, 91, 92, 93, 94, 95, 97, 98, 99, 100, 102, 103, 104, 105, 107, 108, 109, 111,
    112, 113, 115, 116, 117, 119, 120, 121, 123, 124, 126, 127, 128, 130, 131, 133, 134, 136, 137,
    139, 140, 142, 143, 145, 146, 148, 149, 151, 152, 154, 155, 157, 158, 160, 162, 163, 165, 166,
    168, 170, 171, 173, 175, 176, 178, 180, 181, 183, 185, 186, 188, 190, 192, 193, 195, 197, 199,
    200, 202, 204, 206, 207, 209, 211, 213, 215, 217, 218, 220, 222, 224, 226, 228, 230, 232, 233,
    235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255 };
#endif
#endif

/**
 * @brief 伽马校正
 */
static inline uint8_t LEDGamma(uint8_t v)
{
#ifdef LED_USE_GAMMA_CORRECTION
#ifdef LED_USE_PRECALCULATED_GAMMA_TABLE
TED_GAMMA_TABLE
    return LEDGammaTable[v];
#else
    return (v * v + v) >> 8;
#endif
#else
    return v;
#endif
}

#if USE_HSV
#define HUE(h)  ({ typeof(h) h1 = h % 360; h1 < 0 ? 360 + h1 : h1; })
/**
 * @brief HSV转换为RGB
 * @param[in]  hsv      HSV调色空间
 * @param[in]  rgb      RGB颜色空间
 */
void HSV2RGB(HSV_t *hsv, RGB_t *rgb)
{
    if (!hsv->v)
    {
        rgb->r = rgb->g = rgb->b = 0;
    }
    else if (!hsv->s)
    {
        rgb->r = rgb->g = rgb->b = hsv->v;
    }
    else
    {
        int hue = HUE(hsv->h);

        int sector = hue / 60;
        int angle = sector & 1 ? 60 - hue % 60 : hue % 60;

        int high = hsv->v;
        int low = (255 - hsv->s) * high / 255;
        int middle = low + (high - low) * angle / 60;

        switch (sector)
        {
        case 0: // red -> yellow
            rgb->r = high;
            rgb->g = middle;
            rgb->b = low;

            break;

        case 1: // yellow -> green
            rgb->r = middle;
            rgb->g = high;
            rgb->b = low;

            break;

        case 2: // green -> cyan
            rgb->r = low;
            rgb->g = high;
            rgb->b = middle;

            break;

        case 3: // cyan -> blue
            rgb->r = low;
            rgb->g = middle;
            rgb->b = high;

            break;

        case 4: // blue -> magenta
            rgb->r = middle;
            rgb->g = low;
            rgb->b = high;

            break;

        case 5: // magenta -> red
            rgb->r = high;
            rgb->g = low;
            rgb->b = middle;
        }
    }
}
#endif


/**
 * @brief RGB转换为PWM
 * @param[in]  rgb      RGB颜色
 * @param[out] pwm      PWM波形值
 */
static void RGB2PWM( LedDrv_t *obj, RGB_t *rgb, PWM_t *pwm )
{
    uint8_t r = LEDGamma(rgb->r);
    uint8_t g = LEDGamma(rgb->g);
    uint8_t b = LEDGamma(rgb->b);

    uint8_t mask = 0x80;
    uint8_t i;

    switch (obj->CHIP)
    {
    case WS2812:
    {
        for (i = 0; i < 8; i++)
        {
            pwm->b1[i] = b & mask ? LED_PULSE_HIGH : LED_PULSE_LOW;
            pwm->b2[i] = r & mask ? LED_PULSE_HIGH : LED_PULSE_LOW;
            pwm->b3[i] = g & mask ? LED_PULSE_HIGH : LED_PULSE_LOW;
            mask >>= 1;
        }
    } break;

    default:
    {
        for (i = 0; i < 8; i++)
        {
            pwm->b1[i] = b & mask ? obj->led_pulse_high : obj->led_pulse_low;
            pwm->b2[i] = g & mask ? obj->led_pulse_high : obj->led_pulse_low;
            pwm->b3[i] = r & mask ? obj->led_pulse_high : obj->led_pulse_low;
            mask >>= 1;
        }
    } break;
    }
}

/**
 * @brief DMA中断处理函数
 */
void LED_DMA_IRQHANDLER(void)
{
#ifdef STM32F10X
    if (DMA_GetITStatus(LED_DMA_IT_TC) != RESET)    /* 传输完成 */
    {
        DMA_ClearITPendingBit(LED_DMA_IT_TC);
        TIM_Cmd(LED_TIM, DISABLE);
        DMA_Cmd(LED_DMA_CHANNEL, DISABLE);
        // log_d("led dma tc hanppend...\r\n");

        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xSemaphoreGiveFromISR( led_dmaTC_notify, &xHigherPriorityTaskWoken );
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }
#elif defined GD32F10X
    if (dma_interrupt_flag_get( LED_DMA, LED_DMA_CHANNEL, DMA_INT_FLAG_FTF ) != RESET)    /* 传输完成 */
    {
        dma_interrupt_flag_clear( LED_DMA, LED_DMA_CHANNEL, DMA_INT_FLAG_FTF );
        timer_disable( LED_TIM );
        dma_channel_enable( LED_DMA, LED_DMA_CHANNEL );
        // log_d("led dma tc hanppend...\r\n");

        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        xSemaphoreGiveFromISR( led_dmaTC_notify, &xHigherPriorityTaskWoken );
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }
#endif
}

/**
 * @brief 灯带速率计时器处理函数
 */
static void led_time_handler( TimerHandle_t xTimer );

/**
 * @brief LED驱动初始化
 * @param[in]  obj      LED驱动对象
 * @param[in]  chip     LED驱动芯片型号
 * @param[in]  da       数据线
 * @param[in]  nws      级联个数
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 入参错误
 * - @ref BSP_ERROR_NO_MEM - 内存错误
 */
int8_t led_Init( LedDrv_t *obj, LedChip_t chip, PinNames da, uint8_t nws )
{
    if (obj == NULL)
        return BSP_ERROR_INVALID_PARAM;

    obj->CHIP = chip;
    obj->ws_num = nws;

    if (obj->ws_num > (LED_SIZE - LED_RESET_SIZE - LED_START_SIZE))
        obj->ws_num = LED_SIZE - LED_RESET_SIZE - LED_START_SIZE;

    switch (obj->CHIP)
    {
    case WS2812:
    {
        obj->led_pulse_high = 21;
        obj->led_pulse_low = 9;
    } break;

    default:
    {
        obj->led_pulse_high = 21;
        obj->led_pulse_low = 9;
    } break;
    }

    led_dmaTC_notify = xSemaphoreCreateBinary();
    if(led_dmaTC_notify == NULL)
    {
        log_e("led_dmaTC_notify create error\r\n");
        return BSP_ERROR_NO_MEM;
    }

    obj->Lock = xSemaphoreCreateBinary();  /* 初始时信号值为0 */
    if(obj->Lock == NULL)
        return BSP_ERROR_NO_MEM;
    xSemaphoreGive( obj->Lock );

    obj->led_timer = xTimerCreate("led_time", pdMS_TO_TICKS(1000), pdTRUE, obj, led_time_handler);
    if(obj->led_timer == NULL)
    {
        log_e("led_timer create error\r\n");
        return BSP_ERROR_NO_MEM;
    }


#ifdef LED_PINREMAP
    /* 当没有重映射时，TIM3的四个通道CH1，CH2，CH3，CH4分别对应PA6，PA7,PB0,PB1
       当部分重映射时，TIM3的四个通道CH1，CH2，CH3，CH4分别对应PB4，PB5,PB0,PB1
       当完全重映射时，TIM3的四个通道CH1，CH2，CH3，CH4分别对应PC6，PC7,PC8,PC9 */
    GPIO_PinRemapConfig(LED_PINREMAP, ENABLE);
#endif
    GpioInit( &obj->DA, da, PIN_ALTERNATE_FCT, PIN_PUSH_PULL, PIN_NO_PULL, 2 ); /* GPIO_Mode_AF_PP */

#ifdef STM32F10X

#ifdef LED_TIM_APB1_RCC
    RCC_APB1PeriphClockCmd(LED_TIM_APB1_RCC, ENABLE);
#endif
#ifdef LED_TIM_APB2_RCC
    RCC_APB2PeriphClockCmd(LED_TIM_APB2_RCC, ENABLE);
#endif
    RCC_AHBPeriphClockCmd(LED_DMA_AHB_RCC, ENABLE);


    /* 初始化 timer */
    extern uint32_t SystemCoreClock;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseStructInit(&TIM_TimeBaseInitStructure);
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = LED_PERIOD - 1;  /* 800K */
    TIM_TimeBaseInitStructure.TIM_Prescaler = (SystemCoreClock / LED_FREQUENCY) - 1; /* 24M */
	// TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;    /* NOTE:高级定时器 */
    TIM_TimeBaseInit(LED_TIM, &TIM_TimeBaseInitStructure);

    /* 初始化 timer PWM */
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    LED_TIM_OCINIT(LED_TIM, &TIM_OCInitStructure);
    LED_TIM_OCPRELOAD(LED_TIM, TIM_OCPreload_Enable);   /* NOTE:预装载使能，必须使能，否则时序会错乱*/
#ifdef LED_TIM_CtrlPWMOutputs
    LED_TIM_CtrlPWMOutputs(LED_TIM, ENABLE);   /* MOE 主输出使能(高级定时器支持) */
#endif

    /* 初始化 DMA channel */
    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(LED_DMA_CHANNEL);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & LED_TIM_DMA_CCR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) LED_DMABuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = sizeof(LED_DMABuffer) / sizeof(uint16_t);
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(LED_DMA_CHANNEL, &DMA_InitStructure);

    TIM_DMACmd(LED_TIM, LED_TIM_DMA_CC, ENABLE);
    // TIM_DMACmd(LED_TIM, TIM_DMA_Update, ENABLE);

    /* 初始化DMA中断 */
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = LED_DMA_IRQ;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = LED_IRQ_PRIO;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = LED_IRQ_SUBPRIO;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    DMA_ITConfig(LED_DMA_CHANNEL, DMA_IT_TC, ENABLE);

#elif defined GD32F10X
    rcu_periph_clock_enable( LED_TIM_RCU );
    rcu_periph_clock_enable( LED_TIM_DMA_RCU );

    /* 初始化 timer */
    extern uint32_t SystemCoreClock;
    timer_parameter_struct timer_initpara;
    timer_deinit( LED_TIM );
    timer_struct_para_init( &timer_initpara );
    timer_initpara.prescaler         = (SystemCoreClock / LED_FREQUENCY) - 1; /* 24M */
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = LED_PERIOD - 1;  /* 800K */
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;	/* NOTE:高级定时器 */
    timer_init( LED_TIM, &timer_initpara );

    /* 初始化 timer PWM */
    timer_oc_parameter_struct timer_ocintpara;
    timer_channel_output_struct_para_init( &timer_ocintpara );
    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    timer_channel_output_config( LED_TIM, LED_TIM_CH, &timer_ocintpara );
    timer_channel_output_pulse_value_config( LED_TIM, LED_TIM_CH, 0 );
    timer_channel_output_mode_config( LED_TIM, LED_TIM_CH, TIMER_OC_MODE_PWM0 );
    timer_channel_output_shadow_config( LED_TIM, LED_TIM_CH, TIMER_OC_SHADOW_DISABLE );
    timer_auto_reload_shadow_enable( LED_TIM );	/* 使能自动重载影子寄存器 */


    /* 初始化 DMA channel */
    dma_parameter_struct dma_init_struct;
    dma_deinit( LED_DMA, LED_DMA_CHANNEL );
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.periph_addr = (uint32_t) LED_TIM_DMA_CCR;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory_addr = (uint32_t) LED_DMABuffer;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.number = sizeof(LED_DMABuffer) / sizeof(uint16_t);
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init( LED_DMA, LED_DMA_CHANNEL, &dma_init_struct );
    dma_circulation_disable( LED_DMA, LED_DMA_CHANNEL );
    dma_memory_to_memory_disable( LED_DMA, LED_DMA_CHANNEL );

    timer_dma_enable( LED_TIM, LED_TIM_DMA_CC );
    dma_interrupt_enable( LED_DMA, LED_DMA_CHANNEL, DMA_INT_FTF );
#endif

    // log_d("LED_DMABuffer size = %d (%d)(%d)\r\n", sizeof(LED_DMABuffer), sizeof(PWM_t), sizeof(PWM_t)*LED_SIZE);

    obj->IsInitialized = true;

    return BSP_SUCCESS;
}

/**
 * @brief 计算流水的下一个循环RGB序列
 * @param[in]  obj      LED对象
 */
static void led_next_rgbLoop( LedDrv_t *obj )
{
    if (obj->rgb_loop_num > LED_LOOP_SIZE)
        obj->rgb_loop_num = LED_LOOP_SIZE;

    RGB_t rgb_loop_temp[LED_LOOP_SIZE];

    if (obj->lightMode == LED_WATER_MODE)   /* 流水模式 */
    {
        memcpy(&rgb_loop_temp[0], &obj->rgb_loop[obj->rgb_loop_num-1], sizeof(RGB_t));
        memcpy(&rgb_loop_temp[1], &obj->rgb_loop[0], sizeof(RGB_t) * (obj->rgb_loop_num - 1));
        memcpy(obj->rgb_loop, rgb_loop_temp, sizeof(RGB_t) * obj->rgb_loop_num);
    }
    else if (obj->lightMode == LED_GRADUAL_MODE)    /* 渐变模式 */
    {
        
    }
}

/**
 * @brief 更新DMA缓存
 */
static void led_update_DMABuffer( LedDrv_t *obj )
{
    uint8_t i, j;

    memset(LED_DMABuffer, 0, sizeof(PWM_t)*LED_SIZE);   /* 清空 */

    for (i=0; i<(obj->ws_num / obj->rgb_loop_num); i++)
    {
        for (j = 0; j < obj->rgb_loop_num; j++)
        {
            RGB2PWM( obj, &obj->rgb_loop[j], &LED_DMABuffer[i*obj->rgb_loop_num+j] );
        }
    }
    for (i=0; i<(obj->ws_num % obj->rgb_loop_num); i++)
    {
        RGB2PWM( obj, &obj->rgb_loop[i], &LED_DMABuffer[obj->ws_num - obj->ws_num % obj->rgb_loop_num + i] );
    }
}

/**
 * @brief LED PWM控制的DMA发送
 * @param[in]  obj      LED对象
 */
static void led_send( LedDrv_t *obj )
{
#ifdef STM32F10X
    DMA_SetCurrDataCounter(LED_DMA_CHANNEL, (obj->ws_num + LED_START_SIZE + LED_RESET_SIZE)*24);

    DMA_ClearFlag(LED_DMA_IT_GL);
    TIM_Cmd(LED_TIM, ENABLE);
    DMA_Cmd(LED_DMA_CHANNEL, ENABLE);

    xSemaphoreTake( led_dmaTC_notify, 50 );
    // while(!DMA_GetFlagStatus(LED_DMA_IT_TC));
    TIM_Cmd(LED_TIM, DISABLE);
    DMA_Cmd(LED_DMA_CHANNEL, DISABLE);
    // DMA_ClearFlag(LED_DMA_IT_GL);

#elif defined GD32F10X
    dma_transfer_number_config( LED_DMA, LED_DMA_CHANNEL, (obj->ws_num + LED_START_SIZE + LED_RESET_SIZE)*24 );
    dma_flag_clear( LED_DMA, LED_DMA_CHANNEL, DMA_FLAG_G );
    timer_enable( LED_TIM );
    dma_channel_disable( LED_DMA, LED_DMA_CHANNEL );

    xSemaphoreTake( led_dmaTC_notify, 50 );
    // while(!dma_flag_get(DMA_FLAG_FTF));
    timer_disable( LED_TIM );
    dma_channel_enable( LED_DMA, LED_DMA_CHANNEL );
    // dma_flag_clear(DMA_FLAG_G);
#endif
}

static void led_time_handler( TimerHandle_t xTimer )
{
    LedDrv_t *obj = (LedDrv_t *)pvTimerGetTimerID(xTimer);

    led_next_rgbLoop( obj );
    led_update_DMABuffer( obj );
    led_send( obj );
}

/**
 * @brief LED设置
 * @param[in]  obj      LED对象
 * @param[in]  rgb_loop RGB调色数组
 * @param[in]  rgb_loop_num RGB调色数组长度
 * @param[in]  mode     点灯模式
 * @param[in]  speed    点灯速率
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 入参错误
 */
int8_t led_set( LedDrv_t *obj, RGB_t *rgb_loop, uint8_t rgb_loop_num, LightMode_t mode, uint16_t speed )
{
    if ((obj == NULL) || (rgb_loop == NULL))
        return BSP_ERROR_INVALID_PARAM;

    if (!obj->IsInitialized)
    {
        log_e( "LED has no Initialized\r\n" );
        return BSP_ERROR_NO_INIT;
    }

    if (rgb_loop_num > LED_LOOP_SIZE)
        return BSP_ERROR_INVALID_PARAM;
    
    if (speed < 100)
        speed = 100;

    xSemaphoreTake( obj->Lock, portMAX_DELAY );

    obj->rgb_loop_num = rgb_loop_num;
    memcpy(obj->rgb_loop, rgb_loop, sizeof(RGB_t)*rgb_loop_num);
    obj->lightMode = mode;

    xTimerStop( obj->led_timer, 0 );
#ifdef STM32F10X
    TIM_Cmd(LED_TIM, DISABLE);
    DMA_Cmd(LED_DMA_CHANNEL, DISABLE);
    DMA_ClearFlag(LED_DMA_IT_GL);
#elif defined GD32F10X
    timer_disable( LED_TIM );
    dma_channel_enable( LED_DMA, LED_DMA_CHANNEL );
    dma_flag_clear( LED_DMA, LED_DMA_CHANNEL, DMA_FLAG_G );
#endif

    led_update_DMABuffer( obj );
    led_send( obj );

    if (mode == LED_WATER_MODE)
    {
        xTimerChangePeriod( obj->led_timer, pdMS_TO_TICKS( speed ), 0 );
        xTimerStart( obj->led_timer, 0 );
    }

    xSemaphoreGive( obj->Lock );

    return BSP_SUCCESS;
}


#else

extern void hal_delay_us(uint16_t us);

static void led_delay_400ns(void)
{
    __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    __nop();__nop();__nop();
}

static void led_delay_850ns(void)
{
    __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
    __nop();__nop();__nop();
//    __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
//    __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
}

/**
 * @brief LED驱动初始化
 * @param[in]  obj      LED驱动对象
 * @param[in]  chip     LED驱动芯片型号
 * @param[in]  da       数据线
 * @param[in]  nws      级联个数
 * @return int8_t 
 * - @b Sucess : 0 \n
 * - @b Fail : -1
 */
int8_t led_Init( LedDrv_t *obj, LedChip_t chip, PinNames da, uint8_t nws )
{
    if (obj == NULL)
        return -1;

    obj->CHIP = chip;
    obj->ws_num = nws;
    GpioInit( &obj->DA, da, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
    obj->IsInitialized = true;

    return 0;
}

/**
 * @brief 复位数据线
 * @param  obj         LED驱动对象
 */
static void led_Reset( LedDrv_t *obj )
{
    switch (obj->CHIP)
    {
    case WS2812:
        GpioWrite( &obj->DA, 0 );
        hal_delay_us(100);  /* > 50us */
        break;
    
    case TM1914:
        GpioWrite( &obj->DA, 1 );
        hal_delay_us(300);  /* > 200us */
        break;

    default:
        log_e("unsupport LED chip\r\n");
        break;
    }
}

/**
 * @brief LED驱动发送一个字节
 * @param[in]  obj      led驱动对象
 * @param[in]  data     一个灯带颜色
 */
static void led_Sendbyte( LedDrv_t *obj, uint8_t color )
{
    int8_t i;

    switch (obj->CHIP)
    {
    case WS2812:
        for(i=7; i>=0; i--)
        {
            if ( (uint8_t)(color>>i) & 0x01 )
            {
                PBout(4) = 1;
                led_delay_850ns();
                PBout(4) = 0;
                led_delay_400ns();
            }
            else
            {
                PBout(4) = 1;
                led_delay_400ns();
                PBout(4) = 0;
                led_delay_850ns();
            }
        }
        break;

    case TM1914:
        for(i=7; i>=0; i--)
        {
            if ( (uint8_t)(color>>i) & 0x01 )
            {
                PBout(4) = 1;
                led_delay_850ns();
                PBout(4) = 0;
                led_delay_400ns();
            }
            else
            {
                PBout(4) = 1;
                led_delay_400ns();
                PBout(4) = 0;
                led_delay_850ns();
            }
        }
        break;

    default:
        log_e("unsupport LED chip\r\n");
        break;
    }
}

static void led_SendOne( LedDrv_t *obj, RGB_t color )
{
    obj->current_color = color;
    
    switch (obj->CHIP)
    {
    case WS2812:
        led_Sendbyte( obj, color.g );
        led_Sendbyte( obj, color.r );
        led_Sendbyte( obj, color.b );
        break;
    
    case TM1914:
        led_Sendbyte( obj, color.r );
        led_Sendbyte( obj, color.g );
        led_Sendbyte( obj, color.b );
        break;

    default:
        log_e("unsupport LED chip\r\n");
        break;
    }
}

RGB_t color_black = {0,0,0};

int8_t led_Send( LedDrv_t *obj, RGB_t *color )
{
    ENTER_CRITICAL( );
    for(uint8_t i=0; i<obj->ws_num; i++)
    {
        led_SendOne(obj, *color);
//        led_SendOne(obj, color_black);
    }
    led_Reset( obj );
    EXIT_CRITICAL( );
	
	return 0;
}

#endif
#endif


/*********** (C) COPYRIGHT 2020 FiberHome *****END OF FILE****/
